package io.gitee.sfch.chunmi.springframework.util;

import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;

/**
 * IP工具
 */
@Slf4j
public abstract class IpUtil {

    /**
     * 需要根据IP获取的请求头
     */
    private static final String[] HEADERS = {
            // 最常见，优先级最高。
            // 最常见的代理服务器（如 Nginx、Apache、CDN、负载均衡器等）添加的头字段。
            // 如果请求经过多个代理，X-Forwarded-For 会包含一个逗号分隔的 IP 列表。
            // 第一个 IP 是客户端的真实 IP，后面的 IP 是经过的代理服务器 IP。
            "X-Forwarded-For",
            // 一些老版本的代理服务器（如 Apache HTTP Server 或 Squid）可能会使用此头字段。
            // 该字段通常包含客户端的真实 IP。
            "Proxy-Client-IP",
            // 用于 WebLogic 服务器。
            "WL-Proxy-Client-IP",
            // 非标准的 X-Forwarded-For 变体。
            // 一些非标准的代理服务器或自定义实现可能会使用此头字段。
            "HTTP_X_FORWARDED_FOR",
            // 非标准的 X-Forwarded-For 变体。
            "HTTP_X_FORWARDED",
            // 用于集群环境（如 Kubernetes、AWS ELB）。
            "HTTP_X_CLUSTER_CLIENT_IP",
            // 非标准的客户端 IP 头字段。
            // 一些代理服务器或自定义实现可能会使用此头字段。
            "HTTP_CLIENT_IP",
            // 非标准的 X-Forwarded-For 变体。
            "HTTP_FORWARDED_FOR",
            // 非标准的 X-Forwarded-For 变体。
            "HTTP_FORWARDED",
            // 用于标识请求经过的代理服务器。
            // 通常用于标识请求经过的代理服务器，而不是客户端的真实 IP。
            // 在某些情况下，可能会包含客户端的 IP 信息。
            "HTTP_VIA",
            // 默认的客户端 IP 地址，由 Servlet 容器（如 Tomcat）提供。
            "REMOTE_ADDR"
    };

    /**
     * 获取客户端的真实IP地址
     *
     * @param request HttpServletRequest对象
     * @return 客户端的真实IP地址
     */
    public static String getClientIp(HttpServletRequest request) {
        // 遍历所有可能的HTTP头字段，尝试获取IP
        for (String header : HEADERS) {
            String ip = request.getHeader(header);
            if (isValidIp(ip)) {
                log.debug("Found IP {} from header {}", ip, header);
                return extractClientIp(ip);
            }
        }
        String remoteAddr = request.getRemoteAddr();
        // 处理 IPv6 的本地地址
        if ("0:0:0:0:0:0:0:1".equals(remoteAddr) || "::1".equals(remoteAddr)) {
            remoteAddr = "127.0.0.1";
        }
        log.debug("No valid IP found in headers, using remote address: {}", remoteAddr);
        return remoteAddr;
    }

    /**
     * 检查IP地址是否有效
     *
     * @param ip IP地址
     * @return 如果IP地址有效则返回true，否则返回false
     */
    private static boolean isValidIp(String ip) {
        return ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip);
    }

    /**
     * 从IP地址中提取客户端真实IP（处理多个IP的情况），需要考虑IPV6的情况
     *
     * @param ip IP地址
     * @return 客户端真实IP
     */
    private static String extractClientIp(String ip) {
        int i = ip.indexOf(",");
        return i > 0 ? ip.substring(0, i).trim() : ip.trim();
    }
}
